/*
 * $Id: SynchroSetBuilder.java 1259 2007-01-09 14:23:47Z tcoupaye $
 *
 * Behavior Protocols extensions for static and runtime checking
 * developed for the Julia implementation of Fractal.
 *
 * Copyright (C) 2006
 *    Formal Methods In Software Engineering Group
 *    Institute of Computer Science
 *    Academy of Sciences of the Czech Republic
 *
 * Copyright (C) 2006 France Telecom
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 * Contact: ft@nenya.ms.mff.cuni.cz
 * Authors: Jiri Adamek <adamek@nenya.ms.mff.cuni.cz>
 *
 */

package org.objectweb.fractal.bpc.staticchecker.preprocessor;

import org.objectweb.fractal.bpc.staticchecker.*;

import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;

/**
 * This class contains the methods for building sets of synchronizing events
 * and the set of events on unbound interfaces.
 */
public class SynchroSetBuilder {

	/* 
	 * Stores the events (method names) from the 'interfaces' set
	 * into the 'events' event-set.
	 */
	
	private static void iterateInterfaces(EventSet events, Set interfaces) {
		Iterator it = interfaces.iterator();
		while (it.hasNext()) {
			InterfaceInstance inInst = (InterfaceInstance) it.next();
			String prefix = (inInst.frameName == null ? "" : inInst.frameName)
					+ ":" + inInst.interfaceName + ".";
			for (int i = 0; i < inInst.methodNames.length; i++) {
				events.add(prefix + inInst.methodNames[i]);
			}
		}
	}
	
	public static String getUnboundEvents(Set unboundProvidedInterfaces,
			Set unboundRequiredInterfaces) {

		EventSet result = new EventSet();

		iterateInterfaces(result, unboundProvidedInterfaces);
		iterateInterfaces(result, unboundRequiredInterfaces);

		return result.toString();
	}
	
	private static EventSet idetifySynchroEvents(Set bindingSet,
			FrameInstance frame, Map interfaceMap, Map reverseInterfaceMap) {
		
		EventSet result = new EventSet();
		
		for (int i = 0; i < frame.interfaces.length; i++) {
			
			InterfaceInstance inInst = frame.interfaces[i];
			
			Iterator it;
			if (Transformation.isTo(inInst))
				it = ((Set)reverseInterfaceMap.get(inInst)).iterator();
			else
				it = ((Set)interfaceMap.get(inInst)).iterator();
			
			while (it.hasNext()) {

				/* Identify a binding and the corresponding target interface */
				
				InterfaceInstance inInst2 = (InterfaceInstance) it.next();
				Binding binding;
				
				if (Transformation.isTo(inInst)) {
					binding = new Binding(inInst2.frameName,
							inInst2.interfaceName, inInst.frameName,
							inInst.interfaceName);
					
					
				} else {
					binding = new Binding(inInst.frameName,
							inInst.interfaceName, inInst2.frameName,
							inInst2.interfaceName);
					
				}

				/* 
				 * If the binding is in the binding set,
				 * process the events of the binding (and delete the binding from
				 * the binding set) 
				 */
				
				if (bindingSet.contains(binding)) {
					for (int j = 0; j < inInst.methodNames.length; j++)
						result.add(binding.toString() + "." + inInst.methodNames[j]);
					for (int j = 0; j < inInst2.methodNames.length; j++)
						result.add(binding.toString() + "." + inInst2.methodNames[j]);
					bindingSet.remove(binding);
				}
				
			}
			
		}
		
		return result;
	}
	
	public static String[] getSynchroSets(FrameInstance superComponent,
			FrameInstance subcomponents[], Binding[] bindings,
			Map interfaceMap, Map reverseInterfaceMap) {

		/* TODO add assert(subcomponents.length > 0); */

		Set bindingSet = new HashSet();
		for (int i = 0; i < bindings.length; i++)
			bindingSet.add(bindings[i]);

		String[] result = new String[subcomponents.length];

		result[0] = idetifySynchroEvents(bindingSet, superComponent,
				interfaceMap, reverseInterfaceMap).toString();

		for (int i = 0; i < subcomponents.length - 1; i++)
			result[i + 1] = idetifySynchroEvents(bindingSet, subcomponents[i],
					interfaceMap, reverseInterfaceMap).toString();

		/* TODO add assert "ted by mel byt bindingSet prazdny" */

		return result;
	}
}
